#include "server.h"

static int num;        // 用于保存用户好友表的好友个数
struct msg getmsg[50]; // 将结构体做成全局变量，并初始�?

//2024/7/31 23:41:29
// 将接收的用户数据: 账号和密码信�? json解包---可以拓展为解包结构体数据
void json_To_Info(char *p, INFO *info) 
{
    // 解包结构体数�?
    // 1. 将字符串转成json大对�?
    struct json_object *object = json_tokener_parse(p);
    // 2. 根据标签将json大对象解包成json小对�?
    struct json_object *obj_fd = json_object_object_get(object, "fd");
    struct json_object *obj_cmd = json_object_object_get(object, "cmd");
    struct json_object *obj_uid = json_object_object_get(object, "uid");
    struct json_object *obj_passwd = json_object_object_get(object, "passwd");
    struct json_object *obj_msg = json_object_object_get(object, "msg");
    // 3. 将json小对象转换成结构体对�?
    info->fd = json_object_get_int(obj_fd);
    info->cmd = json_object_get_int(obj_cmd);
    strcpy(info->uid, json_object_get_string(obj_uid));
    strcpy(info->passwd, json_object_get_string(obj_passwd));
    strcpy(info->msg, json_object_get_string(obj_msg));
}

//2024-8-4 20:52:59
//将数据打包成json文件进行发送
void info_To_Json (INFO *info, char *buf)
{
    // 1>将结构体id转化为json小对象id;
    struct json_object *obj_fd = json_object_new_int(info->fd);
    struct json_object *obj_cmd = json_object_new_int(info->cmd);
    struct json_object *obj_uid = json_object_new_string(info->uid);
    struct json_object *obj_passwd = json_object_new_string(info->passwd);
    struct json_object *obj_msg = json_object_new_string(info->msg);

    //创建大结构体
    struct json_object *object = json_object_new_object();

    //将小结构体打包到大结构体中
    json_object_object_add(object, "fd", obj_fd);
    json_object_object_add(object, "cmd", obj_cmd);
    json_object_object_add(object, "uid", obj_uid);
    json_object_object_add(object, "passwd", obj_passwd);
    json_object_object_add(object, "msg", obj_msg);
    
    //最后将大结构体转化成字符串，并拷贝到指定地址
    //先清空指定字符串中的内容
    bzero(buf, sizeof(buf));
    //再进行copy
    strcpy(buf, json_object_to_json_string(object));
}
// 登录模块
int log_in(INFO *info)
{
    char buf[512];
    // 将结构体数据和用户注册表中的账号和密码进行比�?
    sqlite3 *ppdb;
    char *errmsg;
    sqlite3_open("uid.db", &ppdb); // 打开数据�?
    // 查询表并进行对比
    // 1. 查询语句
    char sql[200] = "select *from sign_in;";
    int ret = sqlite3_exec(ppdb, sql, compare_info, info, &errmsg);
    printf("ret = %d\n", ret);
    if (ret != SQLITE_OK) { // 回调函数异常结束，表明匹配成功，用户登录成功
        // 登录成功，更新用户注册表，将用户的fd写进�?
        bzero(sql, sizeof(sql));
        sprintf(sql, "update sign_in set user_fd = '%d' where user_uid == '%s';", info->fd, info->uid);
        ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK) {
            syslog(LOG_ERR, "error: %s\n", errmsg);
            return -1;
        }
        // 将正确的账号和密码保存进传入的my_info�?
        //strcpy(my_info->uid, log_info.uid);
        //strcpy (my_info->passwd, log_info.passwd);

        // 向客户端发送登录成功信�?
        info->cmd = BK_LOGIN;
        strcpy(info->msg, "login ok");

        sqlite3_close(ppdb); // 关闭数据?
        return 0;
    }         
    
    printf("Not send\n");
    printf("info->fd = %d\n", info->fd);

    //sig_send(info->fd, "log error"); // 向客户端发送登录失败信�?
    info->cmd = BK_LOGIN;
    bzero(info->msg, sizeof(info->msg));
    strcpy(info->msg, "login error");
    bzero(buf, sizeof(buf));
    info_To_Json(info, buf);
    printf("send buf = %s\n", buf);
    ret = send(info->fd, buf, strlen(buf), 0);
    printf("send ret = %d\n", ret);
    if (ret < 0) {
        perror("send??");
        return 0;
    }
    /*
    //若匹配失败，则需要清空my_info中的账号和密码数据，防止影响后续操作
    bzero(my_info->uid, sizeof(my_info->uid));
    bzero(my_info->passwd, sizeof(my_info->passwd));
    */
    sqlite3_close(ppdb); // 关闭数据�?
    return -1;
}

// 数据库回调函数，登录�?
// 服务器端将接收的用户账号密码数据和数据库用户注册表数据对�?
int compare_info(void *info, int column, char **data, char **name) 
{
    //struct user *log_info = (struct user *)info;
    INFO *log_info = (INFO *)info;
    printf("compare uid = %s\n", log_info->uid);
    if ((!strcmp(log_info->uid, data[0])) && (!strcmp(log_info->passwd, data[1]))) { //当账号和密码同时匹配时，才返�?-1，结束回调函�?
        return -1;
    }
    return 0;
}

//---------------------------------------------------------------------
/*******************功能函数************************/
// 信号发送函数，给套接字为fd的客户端发送字符串数据(信号)
// sig_send(fd, "addto");
void sig_send(int fd, char *sig) 
{
    char buf[50];
    bzero(buf, sizeof(buf));
    strcpy(buf, sig);
    printf("%s\n", sig);
    int ret = send(fd, buf, strlen(buf), 0);
    printf("send ret = %d\n", ret);
    if (ret < 0) {
        perror("send??");
        return;
    }
}



// 数据库回调函数，注册时，接收用户输入的账号密码数据，服务器端检查用户注册表，看是否存在该账�?
int compare_uid(void *info, int column, char **data, char **name) 
{
    struct user *sign_info = (struct user *)info;
    if (!strcmp(sign_info->uid, data[0])) {
        return -1;
    }
    return 0;
}

// 将接收的用户数据: 账号和密码信�? json解包---可以拓展为解包结构体数据
void json_user(char *p, void *info) {
  // 解包结构体数�?
  // 1. 将字符串转成json大对�?
  struct json_object *object = json_tokener_parse(p);
  // 2. 根据标签将json大对象解包成json小对�?
  struct json_object *obj_uid = json_object_object_get(object, "uid");
  struct json_object *obj_passwd = json_object_object_get(object, "passwd");
  // 3. 将json小对象转换成结构体对�?
  struct user *log_info = (struct user *)info;
  strcpy(log_info->uid, json_object_get_string(obj_uid));
  strcpy(log_info->passwd, json_object_get_string(obj_passwd));
}

// 接收用户账号和密码信�?---可以拓展为接收结构体数据
void info_recv(int fd, void *arg)
{
    struct user *info = (struct user *)arg;
    char buf[100];
    bzero(buf, sizeof(buf));
    int ret = recv(fd, buf, sizeof(buf), 0);
    if (ret < 0) {
        perror("recv");
        return;
    }
    json_user(buf, info); // 解包数据
}

// 数据库回调函数，根据好友的uid获取好友的fd
int get_fd(void *info, int column, char **data, char **name)
{
    struct fd *talk_fd = (struct fd *)info;
    talk_fd->b_fd = atoi(data[0]);

    return 0;
}

// 数据库回调函数，根据fd获取自己uid
int my_uid(void *info, int column, char **data, char **name)
{ // 查询自己的id
  // 传入的参数名为info; 列的个数�?: column; 数据保存的地方为: date[]; 列名�?:
  // name[] 查找到fd所在列
  struct user *my_info = (struct user *)info;
  strcpy(my_info->uid, data[0]); // 获取自身id

  return 0;
}

// 线程: 服务器端信息转发线程
void *br_info(void *arg) {
  // 先保存发送双方的fd
  struct fd *talk_fd = (struct fd *)arg;

  // 发送信息的长度
  char buf[100];
  while (1) {
    bzero(buf, sizeof(buf));
    recv(talk_fd->b_fd, buf, sizeof(buf), 0);
    send(talk_fd->fd, buf, strlen(buf), 0);
    // 关闭私聊信号
    if (!strcmp(buf, "$$")) { // 私聊通道关闭
      pthread_exit(NULL);
    }
  }
}

// 回调函数, 获取用户好友uid信息
int get_bro_list(void *arg, int column, char **data, char **name)
{
    struct bro *bro_info = (struct bro *)arg;
    strcpy(bro_info[num].uid, data[0]); // 把好友uid存储结构体中
    num++;                              // 全局变量，用于计算好友数
    return 0;
}

// 将结构体数组struct bro bro_list[num]打包成json数组对象
void brolist_json(void *info, char *buf) {
  // 创建一个json数组对象
  struct json_object *obj_arr = json_object_new_array();

  struct bro *bro_info = (struct bro *)info;
  struct json_object *object;
  struct json_object *obj_uid;
  struct json_object *obj_status;
  int i;
  for (i = 0; i < num; i++) { // 打包num个结构体数据
    // 1>创建json大对�?(大箱�?=object)
    object = json_object_new_object();

    // 2>将数据结构体打包成小对象
    obj_uid = json_object_new_string(bro_info[i].uid);
    obj_status = json_object_new_int(bro_info[i].status);

    // 3>将json小对象打包进json大对象，并标�?
    json_object_object_add(object, "uid", obj_uid);
    json_object_object_add(object, "status", obj_status);

    // 4>将json大对象放入json数组对象�?
    json_object_array_add(obj_arr, object);
  }
  strcpy(buf, json_object_to_json_string(obj_arr));
}

// 将结构体数组struct msg my_msg[num]打包成json数组对象
void msg_json(void *info, char *buf)
{
    // 创建一个json数组对象
    struct json_object *obj_arr = json_object_new_array();

    struct msg *my_msg = (struct msg *)info;
    struct json_object *object;
    struct json_object *obj_message;
    int i;
    for (i = 0; i < num; i++) { // 打包num个结构体数据
        // 1>创建json大对�?(大箱�?=object)
        object = json_object_new_object();

        // 2>将数据结构体打包成小对象
        obj_message = json_object_new_string(my_msg[i].message);

        // 3>将json小对象打包进json大对象，并标�?
        json_object_object_add(object, "message", obj_message);

        // 4>将json大对象放入json数组对象�?
        json_object_array_add(obj_arr, object);
    }
    strcpy(buf, json_object_to_json_string(obj_arr));
}

// 获取好友的状�?
int get_bro_status(void *info, int column, char **data, char **name)
{
    struct bro *bro_info = (struct bro *)info;
    if (atoi(data[0]) > 0) {
        bro_info->status = 1;
    } else {
        bro_info->status = 0;
    }
    return 0;
}

// 判断字符串arr是否�?0
int is_zero(char *arr, int len)
{
    int i;
    for (i = 0; i < len; i++) {
        if (arr[i] != 0)
            return 0;
    }
    return 1;
}

// 将struct user结构体打包成json
void info_json(void *info, char *buf) {
  struct user *user_info = (struct user *)info;
  // 将注册的账号密码json打包
  // 1>将结构体id转化为json小对象id;
  struct json_object *obj_uid = json_object_new_string(user_info->uid);
  struct json_object *obj_passwd = json_object_new_string(user_info->passwd);

  // 2>创建json大对�?(大箱�?=object)
  struct json_object *object = json_object_new_object();

  // 3>将json小对象放入大对象中，并给每个小对象打上标签key
  json_object_object_add(object, "uid", obj_uid);
  json_object_object_add(object, "passwd", obj_passwd);

  // 4>将json大对象转化为字符�?
  strcpy(buf, json_object_to_json_string(object));
  //*buf = json_object_to_json_string(object);
}

// 回调函数: 用于同步服务器和本地的聊天记�?
int get_msg(void *info, int column, char **data, char **name)
{
    struct sql *date_name = (struct sql *)info;
    // strcpy(tab_name, buf); //将参数传入tab_name�?
    // struct msg *my_msg = (struct msg *)info;
    strcpy(getmsg[num].message, data[1]);
    // 必须在同一回调函数内，取用数据的同时将状态进行修改，将数据的状态修改为0,表示已经取出
    char sql[500] = {0};
    sqlite3 *ppDb;
    char *errmsg;
    //打开数据�?
    sqlite3_open(date_name->sql_name, &ppDb);
    //将status修改�?0
    sprintf(sql, "update '%s' set status = 0 where message == '%s';", date_name->tab_name, data[1]);
    int ret = sqlite3_exec(ppDb, sql, NULL, NULL, &errmsg);
    if (ret != SQLITE_OK) {
        printf("error!: %s\n", errmsg);
        return -1;
    }
    num++; // 执行一遍，即一条数据，num+1, num数为数据长度
    return 0;
}

void end_sig(int arg) { pthread_exit(NULL); }

// 线程: 用于同步服务器端和本地的聊天记录
// 该线程的结束条件还没有确�?
void *sys_msg(void *arg)
{
    struct fd *talk_fd = (struct fd *)arg;
    // 打开用户的数据库，根据brouid找到表名，再将数据取出来
    // 1. 打开账号数据�?
    sqlite3 *ppdb;
    char *errmsg;
    sqlite3_open("uid.db", &ppdb);
    // 2.根据用户的fd查找用户的uid
    struct user my_info = {0}; // 将用户的uid保存在info.uid�?
    char sql[200];
    bzero(sql, sizeof(sql));
    sprintf(sql, "select user_uid from sign_in where user_fd == '%d';", talk_fd->fd);
    int ret = sqlite3_exec(ppdb, sql, my_uid, &my_info, &errmsg);
    if (ret != SQLITE_OK) {
        printf("error: %s\n", errmsg);
        return NULL;
    }
    // 3. 根据好友的fd查找好友的uid
    struct user bro_info = {0};
    bzero(sql, sizeof(sql));
    sprintf(sql, "select user_uid from sign_in where user_fd == '%d';", talk_fd->b_fd);
    ret = sqlite3_exec(ppdb, sql, my_uid, &bro_info, &errmsg);
    if (ret != SQLITE_OK) {
        printf("error: %s\n", errmsg);
        return NULL;
    }
    // 4. 关闭账号数据�?
    sqlite3_close(ppdb);
    // 5. 将自己的数据库名称和好友聊天信息表名保存进name�?
    struct sql name;  //声明一个结构体，用于保存信�?
    // 1>确定用户数据库名�?
    char sql_name[60] = {0};
    strcpy(sql_name, my_info.uid);
    strcat(sql_name, ".db");
    // 2>将数据库名保存进结构体中
    strcpy(name.sql_name, sql_name);
    // 3>根据好友uid确定好友给自己发送数据的表名
    char tab_name[60] = "_";
    strcat(tab_name, bro_info.uid); // 此tab_name为用户数据库中，好友给自己发送的信息的数据表
    strcpy(name.tab_name, tab_name);
    // 6. 打开自己的数据库
    sqlite3 *ppDb;
    sqlite3_open(sql_name, &ppDb);
    // 8. 因为该表可能同时被好友在操作，所以表中的信息是实时变化的
    // 使用循环，实时获取表中status�?1(未取�?)的数据，并将其打包发送给客户�?
    while (1) {
        num = 0; // 借用全局变量，用于保存数据的长度，循环每次检索需要将全局变量�?0;
        // 创建一个结构体数组，用于保存每次检索取出的数据
        bzero(getmsg, sizeof(getmsg)); // 将结构体数据�?0
        // struct msg getmsg[50] = {0};  //将结构体做成全部变量，并初始�?
        bzero(sql, sizeof(sql));
        // 筛选出status == 1的数据，并将其保存在结构体数组中
        sprintf(sql, "select *from '%s' where status == 1;", tab_name);
        ret = sqlite3_exec(ppDb, sql, get_msg, &name, &errmsg);
        if (ret != SQLITE_OK) {
          printf("error: %s\n", errmsg);
          return NULL;
        }
        // 此时getmsg数组中已经保存了一次检索需要发送的数据
        // 将结构体数据打包
        char buf[10000];
        bzero(buf, sizeof(buf));
        if(is_zero(getmsg[0].message, 100)){
            sig_send(talk_fd->fd, "NoneMsg"); // 没有信息，发送NULL信号
        } else {
            msg_json(getmsg, buf); // 将getmsg打包，保存进buf�?
            send(talk_fd->fd, buf, strlen(buf), 0); // 发送数�?
        }
    }
    signal(SIGINT, end_sig);
}

/*******************主函�?************************/
// 将服务器做成守护进程
void defend_pro(void) { // 创建守护进程
  if (fork() != 0) {    // 杀死父进程
    exit(-1);
  }

  if (setsid() != 0) { // 将子进程独立成终端进�?
    perror("setsid");
    return;
  }
  if (fork() != 0) { // 杀死子进程
    exit(-1);
  }

  int i;
  int j = sysconf(_SC_OPEN_MAX);
  for (i = 0; i <= j; i++) { // 关闭所有文件描述符
    close(i);
  }

  chdir("/");                         // 将工作目录改为根目录
                                      //
  umask(0);                           // 将创建文件权限掩码修改为0
                                      //
                                      //
  int fd = open("/dev/null", O_RDWR); // 关闭1�?2 �?3
  if (fd < 0) {
    perror("open");
    return;
  }
  dup(0);
  dup(0);
}



// 注册模块
/*int sign_in(void *arg)
{
    int fd = *((int *)arg);
    struct user sign_info;  //用于保存用户注册数据
    info_recv(fd, &sign_info);

    //将结构体数据和用户注册表中的账号进行比较
    sqlite3 *ppdb;
    char *errmsg;
    sqlite3_open("1.db", &ppdb);
    //查询表并进行对比
    //1. 查询语句
    char sql[200] = "select *from sign_in;";
    int ret = sqlite3_exec(ppdb, sql, compare_uid, &sign_info, &errmsg);
    if(ret != SQLITE_OK){  //回调函数异常
        sig_send(fd, "sign error");  //数据库中存在同名账号，发送注册失败信�?
        sqlite3_close(ppdb);  //关闭数据�?
        return -1;
    }else{  //用户不存在于注册表，将用户信息写入注册表�?
        //将信息写入注册表�?
        bzero(sql, sizeof(sql));
        sprintf(sql, "insert into sign_in values('%s', '%s', '%d');",
sign_info.uid, sign_info.passwd, -1); ret = sqlite3_exec(ppdb, sql, NULL, NULL,
&errmsg); if(ret != SQLITE_OK){ printf("error: %s\n", errmsg); return -1;
        }

        //并创建用户好友表
        char buf[60] = "_";
        bzero(sql, sizeof(sql));
        //规定用户好友的名字以下划线开头后接用户的uid，如"_12354";
        strcat(buf, sign_info.uid);
        //创建用户好友�?
        sprintf(sql, "create table if not exists '%s'(user_uid char[50]);",
buf); ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg); if(ret != SQLITE_OK){
            printf("error: %s\n", errmsg);
            return -1;
        }
        //关闭数据�?
        sqlite3_close(ppdb);

        //传送注册成功信�?
        sig_send(fd, "sign ok");

        return 0;
    }

}
*/

// 注册模块
int sign_in(INFO *info)
{
    //struct user *my_info = (struct user *)info;
    //struct user sign_info; // 用于保存用户注册数据
    //info_recv(info->fd, &sign_info);

    // 将结构体数据和用户注册表中的账号进行比较
    sqlite3 *ppdb;
    char *errmsg;
    sqlite3_open("uid.db", &ppdb);
    // 查询表并进行对比
    // 1. 查询语句
    char sql[200] = "select *from sign_in;";
    int ret = sqlite3_exec(ppdb, sql, compare_uid, &info, &errmsg);
    if (ret != SQLITE_OK) { // 回调函数异常
        sig_send(info->fd, "sign error"); // 数据库中存在同名账号，发送注册失败信�?
        sqlite3_close(ppdb); // 关闭数据�?
        return -1;
    } else { // 用户不存在于注册表，将用户信息写入注册表�?
        // 将信息写入注册表�?
        bzero(sql, sizeof(sql));
        sprintf(sql, "insert into sign_in values('%s', '%s', '%d');", info->uid, info->passwd, -1);
        ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK) {
            printf("error: %s\n", errmsg);
            return -1;
        }

        // 并创建用户好友表
        char buf[60] = "_";
        bzero(sql, sizeof(sql));
        // 规定用户好友的名字以下划线开头后接用户的uid，如"_12354";
        strcat(buf, info->uid);
        // 创建用户好友�?
        sprintf(sql, "create table if not exists '%s'(user_uid char[50]);", buf);
        ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK) {
            printf("error: %s\n", errmsg);
            return -1;
        }
        // 关闭数据�?
        sqlite3_close(ppdb);

        // 创建账号独立的数据库
        // 1.数据库名�?"uid.db";
        bzero(buf, sizeof(buf));
        strcpy(buf, info->uid);
        strcat(buf, ".db");

        // 2. 创建数据�?
        sqlite3 *ppDb;
        sqlite3_open(buf, &ppDb);

        // 3. 关闭数据�?
        sqlite3_close(ppDb);

        // 传送注册成功信�?
        sig_send(info->fd, "sign ok");

        return 0;
    }
}

// 账号注销
int log_out(void *info)
{
    struct user *my_info = (struct user *)info;
    char *errmsg;
    // 1. 打开数据�?
    sqlite3 *ppdb;
    sqlite3_open("uid.db", &ppdb);

    char sql[100];
    bzero(sql, sizeof(sql));
    // 注销时，将所有fd等于用户的fd的fd改为-1
    // 实际上只需要改一个也只有一�?
    sprintf(sql, "update sign_in set user_fd = '%d' where user_fd == '%d';", -1, my_info->fd);
    int ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg);
    if (ret != SQLITE_OK) { // 一定是登录后才有注册操作，所以用户的fd一定存�?
        syslog(LOG_ERR, "error: %s", errmsg);
        return -1;
    }
    // 关闭数据�?
    sqlite3_close(ppdb);

    //清空账号和密码数�?
    bzero(my_info->uid, sizeof(my_info->uid));
    bzero(my_info->passwd, sizeof(my_info->passwd));

    return 0;
}

// 私聊函数
/*int talk_to(void *arg)
{
    //创建结构�?, 用于保存沟通双方的fd
    struct fd talk_fd;
    //创建字符数组，用于保存接收和发送的数据
    char buf[100];

    talk_fd.fd = *((int *)arg); //保存自己的fd;

    //接收好友的uid信息，保存在bro_info.uid�?
    struct user bro_info = {0};
    info_recv(talk_fd.fd, &bro_info);

    sqlite3 *ppdb;
    char *errmsg;
    //打开数据�?
    sqlite3_open("1.db", &ppdb);

    //根据好友的uid找到其fd，将其保存在talk_fd.b_fd�?, 并判�?
    char sql[100];
    bzero(sql, sizeof(sql));
    sprintf(sql, "select user_fd from sign_in where user_uid == '%s';",
bro_info.uid); int ret = sqlite3_exec(ppdb, sql, get_fd, &talk_fd, &errmsg);
    //如果语句执行失败，返回错误码
    if(ret != SQLITE_OK){
        printf("error: %s\n", errmsg);
        return -1;
    }else{  //成功表明已获取好友b_fd
        if(talk_fd.b_fd < 0){  //若好友fd小于0，则离线发�?
            sig_send(talk_fd.fd, "talk error");
            //离线操作
        }else{  //好友fd大于0,则在线发�?
            //先给好友发送一个信号，表明有信息到
            //sig_send(talk_fa.b_fd, "News");
//好友根据该信号进行跳转，并与用户建立链接通道

            //转发好友发送的信息
            pthread_t talk;
            pthread_create(&talk, NULL, br_info, &talk_fd);

            //转发用户发送的信息
            while(1){
                bzero(buf, sizeof(buf));
                recv(talk_fd.fd, buf, sizeof(buf), 0);
                send(talk_fd.b_fd, buf, strlen(buf), 0);
                if(!strcmp(buf, "$$")){   //私聊通道关闭
                    //如果接收�?"$$"，服务其除了给好友发送结束信号外，还需要给用户自己返回一个结束信号，用于终止用户接收信号
                    sig_send(talk_fd.fd, "$$");
                    return 0;
                }
            }
        }
    }
}
*/

int talk_to(void *arg)
{
    struct user *my_info = (struct user *)arg;
    // 创建结构�?, 用于保存沟通双方的fd
    struct fd talk_fd;
    talk_fd.fd = my_info->fd; // 保存自己的fd;

    // 创建字符数组，用于保存接收和发送的数据
    char buf[100];

    // 接收好友的uid信息，保存在bro_info.uid�?
    struct user bro_info = {0};
    info_recv(talk_fd.fd, &bro_info);

    sqlite3 *ppdb;
    char *errmsg;
    // 打开数据�?
    sqlite3_open("uid.db", &ppdb);

    // 根据好友的uid找到其fd，将其保存在talk_fd.b_fd�?, 并判�?
    char sql[200];
    bzero(sql, sizeof(sql));
    sprintf(sql, "select user_fd from sign_in where user_uid == '%s';", bro_info.uid);
    int ret = sqlite3_exec(ppdb, sql, get_fd, &talk_fd, &errmsg);
    // 如果语句执行失败，返回错误码
    if (ret != SQLITE_OK) {
        printf("error: %s\n", errmsg);
        return -1;
    } else { // 成功表明已获取好友b_fd
        // 好友在线�?, 先给好友发送消息，告诉好友有人给他发消息，再将数据写入服务器端的数据库�?
        if (talk_fd.b_fd > 0) {
            // 1. 先给好友发送一个信号，表明有信息到
            sig_send(talk_fd.b_fd, "newtalk");
            // 2. 告诉好友是谁发送的信号
            bzero(buf, sizeof(buf));
            info_json(my_info, buf);
            // 3. 打包发送数�?
            send(talk_fd.b_fd, buf, strlen(buf), 0);
        }
        //给自己返回一个信号，表明后续有聊天数据到�?
        sig_send(talk_fd.fd, "sys msg");
        //将好友的uid信息返回
        bzero(buf, sizeof(buf));
        info_json(&bro_info, buf);
        send(talk_fd.fd, buf, strlen(buf), 0);

        // 创建一个线程，用于同步服务器和客户端本地的聊天文件
        pthread_t Sysmsg;
        pthread_create(&Sysmsg, NULL, sys_msg, &talk_fd);

        // 将写入的内容保存进好友数据库的聊天记录表�?
        // 1. 确定好友的数据库名称
        char sql_name[60] = {0};
        strcpy(sql_name, bro_info.uid);
        strcat(sql_name, ".db");
        // 2. 打开好友数据�?
        sqlite3 *broppdb;
        sqlite3_open(sql_name, &broppdb);
        // 3. 根据自己的fd找到自己的uid
        /*传入自己的信息后，就不需要这一步了
        struct user my_info; // 将用户的uid保存在info.uid�?
        bzero(sql, sizeof(sql));
        sprintf(sql, "select *from sign_in where user_fd == '%d';", talk_fd.fd);
        ret = sqlite3_exec(ppdb, sql, my_uid, &my_info, &errmsg);
        if (ret != SQLITE_OK) {
            printf("error: %s\n", errmsg);
            return -1;
        }
        */
        // 3. 根据自己的uid确定自己在好友数据库中的聊天�?
        char tab_name[60] = "_";
        strcat(tab_name, my_info->uid);
        // 5. 此时自己传输给好友的数据都应被写入好友数据库中的聊天表中
        while (1) {
            bzero(buf, sizeof(buf));
            recv(talk_fd.fd, buf, sizeof(buf), 0);
            if (!strcmp(buf, "$$")) { // 如果发�?$$,表明停止发送，退出程�?
                pthread_kill(Sysmsg, SIGINT); // 给线程发送信号，结束线程
                break;
            }
            bzero(sql, sizeof(sql));
            sprintf(sql, "insert into '%s' values(1, '%s');", tab_name, buf);
            ret = sqlite3_exec(broppdb, sql, NULL, NULL, &errmsg);
            if (ret != SQLITE_OK) {
                printf("error: %s\n", errmsg);
                return -1;
            }
        }
        sqlite3_close(broppdb);
    }
    return 0;
}

// 获取用户好友数据: 好友uid，好友状�?(在线,离线)
int get_brolist(void *arg)
{
    // 每次调用该函数，需要先将全局变量�?0
    num = 0;
    // 接收用户的fd
    struct user *my_info = (struct user *)arg;

    // 根据用户的fd查找用户的uid
    //struct user info; // 将用户的uid保存在info.uid�?
    // 1. 打开数据�?
    sqlite3 *ppdb;
    char *errmsg;
    sqlite3_open("uid.db", &ppdb);

    /*
    // 2. 查找用户注册表中user_fd等于fd的项
    char sql[100];
    bzero(sql, sizeof(sql));
    sprintf(sql, "select *from sign_in where user_fd == '%d';", fd);
    int ret = sqlite3_exec(ppdb, sql, my_uid, &info, &errmsg);
    if (ret != SQLITE_OK) {
        printf("error: %s\n", errmsg);
        return -1;
    }
    */
    // 根据用户uid找到用户好友表，并将里面的数据取出来
    // 1.确定用户好友�?
    char tab_name[60] = "_";
    strcat(tab_name, my_info->uid); // 此时tab_name为用户好友表的表�?
    // 声明用户好友表里好友信息结构�?
    // 规定用户好友最�?20�?
    struct bro bro_list[20] = {0};
    char sql[100] = {0};
    // 2. 将用户好友表数据全部保存进结构体�?
    sprintf(sql, "select *from '%s';", tab_name);
    int ret = sqlite3_exec(ppdb, sql, get_bro_list, bro_list, &errmsg);
    if (ret != SQLITE_OK) {
        printf("error: %s\n", errmsg);
        return -1;
    }
    // 根据好友的uid，去用户注册表中查找好友状�?,并保�?
    int i;
    for (i = 0; i < num; i++) {
        bzero(sql, sizeof(sql));
        sprintf(sql, "select user_fd from sign_in where user_uid == '%s';", bro_list[i].uid);
        ret = sqlite3_exec(ppdb, sql, get_bro_status, &bro_list[i], &errmsg);
        if (ret != SQLITE_OK) {
            printf("error: %s\n", errmsg);
            return -1;
        }
    }

    // 将bro_list打包发�?
    char buf[1000];
    bzero(buf, sizeof(buf));
    if (is_zero(bro_list[0].uid, 50)) { // 如果保存的第一好友的uid数据置零，则说明用户没有好友信息
        sig_send(my_info->fd, "NULL"); // 没有好友，发送NULL信号
    } else {
        brolist_json(bro_list, buf);   // 将bro_list打包，保存进buf�?
        send(my_info->fd, buf, strlen(buf), 0); // 发送数�?
    }
    return 0;
}

/*
void *send_add(void *arg)
{
    struct fd *talk_fd = (struct fd *)arg;

}
*/

// 添加好友操作--添加方逻辑函数
int add_bro(void *info) // 处理添加信号
{
    struct user *my_info = (struct user *)info;
    struct fd talk_fd;
    talk_fd.fd = my_info->fd; // 将自己的fd保存在结构体struct fd中，talk_fd.fd
    // 打开日志
    openlog("ikun", LOG_PID, LOG_DAEMON);

    // 打开数据�?
    sqlite3 *ppdb;
    char *errmsg;
    sqlite3_open("uid.db", &ppdb); // 打开数据�?

    // 接收好友uid信息
    struct user bro_info; // 添加
    info_recv(talk_fd.fd, &bro_info);

    // 用户根据uid确定自己的好友表表名
    char tab_name[60] = "_";        // 表名以_开�?
    strcat(tab_name, my_info->uid); // tab_name是用户好友表的表�?

    // 查找添加的好友uid在用户注册表中是否存�?
    char sql[200];
    bzero(sql, sizeof(sql));
    strcpy(sql, "select * from sign_in;"); // 查询注册�?
    int ret = sqlite3_exec(ppdb, sql, compare_uid, &bro_info, &errmsg);
    if (ret == SQLITE_OK){  //回调函数正常返回，说明注册表中不存在好友uid
        sig_send(talk_fd.fd, "add error"); // 给用户发送添加失败信�?
        // 关闭数据�?
        sqlite3_close(ppdb);
        // 关闭日志
        closelog();
        return -1;
    } else { // 回调函数返回非零值中途退出，说明待添加用户存在于注册表中
        // 再判断账号是否是自己的账�?
        if (!strcmp(my_info->uid, bro_info.uid)){
            sig_send(talk_fd.fd, "add error2"); //添加错误，无法添加自己为好友
            //关闭数据�?
            sqlite3_close(ppdb);
            //关闭日志
            closelog();
            return -1;
        }
        // 继续查询用户添加的好友uid是否已经存在于用户好友表�?
        bzero(sql, sizeof(sql));
        sprintf(sql, "select * from '%s';", tab_name); // 查询自己的好友表中是否存在待添加用户uid
        ret = sqlite3_exec(ppdb, sql, compare_uid, &bro_info, &errmsg);
        if (ret != SQLITE_OK) { // 若回调函数中途退出，则说明好友uid已存在于好友表中
            sig_send(talk_fd.fd, "add error1"); // 给用户发送添加失败信�?---该用户已是您的好友！
            // 关闭数据�?
            sqlite3_close(ppdb);

            // 关闭日志
            closelog();
            return -1;
        }
        // 否则--尝试给待添加的好友发送添加好友信�?
        // 先给客户端返回一个ok信号
        sig_send(talk_fd.fd, "add ok");
        // 1. 先根据好友的uid，从注册表中取出其fd
        bzero(sql, sizeof(sql));
        sprintf(sql, "select user_fd from sign_in where user_uid == '%s';", bro_info.uid);
        ret = sqlite3_exec(ppdb, sql, get_fd, &talk_fd, &errmsg); // 此时talk_fd.b_fd保存了待添加好友的fd.
        if (ret != SQLITE_OK) { // 非法情况都刷选出来了，所以一定能取出fd
            syslog(LOG_ERR, "error: %s\n", errmsg);
            return -1;
        }
        // 判断好友是否在线
        if (talk_fd.b_fd < 0) { // 好友不在�?
            // 将添加信号保存到服务器信号表�?
            bzero(sql, sizeof(sql));
            sprintf(sql, "insert into _sig values('add_bro', '%s', '%s');", my_info->uid, bro_info.uid);
            ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg);
            if (ret != SQLITE_OK) {
                syslog(LOG_ERR, "error: %s\n", errmsg);
                return -1;
            }
        } else { // 否则直接给好友发送添加好友信号，并将自己的uid发送过�?
            /*
            pthread_t Sendadd;
            pthread_create(&Sendadd, NULL, send_add, &talk_fd);
            */
            char buf[100] = {0};
            strcpy(buf, "bro add");
            send(talk_fd.b_fd, buf, sizeof(buf), 0);
            // sig_send(talk_fd.b_fd, "broadd");  //被动，代表有人添加自己为好友
            // recv(talk_fd.b_fd, buf, sizeof(buf), 0);

            // 将自己的信息结构体数据my_info打包发�?
            bzero(buf, sizeof(buf));
            info_json(&my_info, buf);
            printf("%s\n", buf);

            // 服务器将添加好友的客户端的uid打包发送给待添加的客户�?
            send(talk_fd.b_fd, buf, strlen(buf), 0);
        }
    }
    closelog();
    return 0;
}

// 数据库回调函数，用于查找用户好友表里的是否存在好友uid
/*int bro_uid(void *info, int column, char **data, char **name)
{
    struct user *bro_info = (struct user *)info;
        if(!strcmp(bro_info->uid, data[0])){
                return -1;
        }
    return 0;
}
*/

/*int agree_add(void *arg)
{
    int fd = *((int *)arg);
    struct user bro_info; //待同意添加的好友的uid
    info_recv(fd, &bro_info); //接收好友的uid, 并保存在bro_info.uid�?

    //打开数据�?
    sqlite3 *ppdb;
    char *errmsg;
    sqlite3_open("1.db", &ppdb);

    //先根据自己的fd，找到自己的uid, 进而找到自己的用户好友�?
    //1.根据fd，确定自己的uid
        struct user my_info = {0};  //声明信息结构�?
        char sql[100];           //sql操作
        bzero(sql,sizeof(sql));
        sprintf(sql, "select * from sign_in where user_fd=='%d';", fd);

        int ret = sqlite3_exec(ppdb, sql, my_uid, &my_info,
&errmsg);//查询自己的uid if(ret != SQLITE_OK){ printf("error: %s\n", errmsg);
        return -1;
    }//my_info.uid中保存了自己的uid

    //2. 用户根据uid确定自己的好友表表名
        char tab_name[60] = "_";  //表名以_开�?
        strcat(tab_name, my_info.uid);     //tab_name是用户好友表的表�?

    //3. 往自己的用户好友表中插入好友的uid--bro_info.uid
    bzero(sql, sizeof(sql));
    sprintf(sql, "insert into '%s' values('%s');", tab_name, bro_info.uid);
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg);
    if(ret != SQLITE_OK){
        printf("error: %s\n", errmsg);
        return -1;
    }

    //根据好友的uid找到好友�?<用户好友�?>,往其内添加自己的uid
        bzero(tab_name,sizeof(tab_name));
    strcpy(tab_name,"_");  //中间变量，重新赋�?
    strcat(tab_name, bro_info.uid);
    //往好友的用户好友表中插入自己的uid--my_info.uid
    bzero(sql, sizeof(sql));
    sprintf(sql, "insert into '%s' values('%s');", tab_name, my_info.uid);
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg);
    if(ret != SQLITE_OK){
        printf("error: %s\n", errmsg);
        return -1;
    }

    sqlite3_close(ppdb);
    return 0;
}*/

int agree_add(void *info)
{
    // struct fd talk_fd;
    struct user *my_info = (struct user *)info;
    // int fd = *((int *)arg);
    struct user bro_info = {0};              // 待同意添加的好友的uid
    info_recv(my_info->fd, &bro_info); // 接收好友的uid, 并保存在bro_info.uid�?
                                     //
    // 打开日志
    openlog("ikun", LOG_PID, LOG_DAEMON);

    // 打开数据�?
    sqlite3 *ppdb;
    char *errmsg;
    sqlite3_open("uid.db", &ppdb);

    // 先根据自己的fd，找到自己的uid, 进而找到自己的用户好友�?
  /*
  //1.根据fd，确定自己的uid
      struct user my_info = {0};  //声明信息结构�?
      char sql[200];           //sql操作
      bzero(sql,sizeof(sql));
      sprintf(sql, "select * from sign_in where user_fd=='%d';", fd);

      int ret = sqlite3_exec(ppdb, sql, my_uid, &my_info,
  &errmsg);//查询自己的uid if(ret != SQLITE_OK){ printf("error: %s\n", errmsg);
      return -1;
  }//my_info.uid中保存了自己的uid
  */
  // my_info->uid中有自己的uid

    // 2. 用户根据uid确定自己的好友表表名
    char tab_name[60] = "_";        // 表名以_开�?
    strcat(tab_name, my_info->uid); // tab_name是用户好友表的表�?

    // 3. 往自己的用户好友表中插入好友的uid--bro_info.uid
    char sql[200];
    bzero(sql, sizeof(sql));
    sprintf(sql, "insert into '%s' values('%s');", tab_name, bro_info.uid);
    int ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg);
    if (ret != SQLITE_OK) {
        syslog(LOG_ERR, "error: %s\n", errmsg);
        // 关闭日志
        closelog();
        // 关闭数据�?
        sqlite3_close(ppdb);
        return -1;
    }

    // 根据好友的uid找到好友�?<用户好友�?>,往其内添加自己的uid
    bzero(tab_name, sizeof(tab_name));
    strcpy(tab_name, "_");
    strcat(tab_name, bro_info.uid);
    // 往好友的用户好友表中插入自己的uid--my_info.uid
    bzero(sql, sizeof(sql));
    sprintf(sql, "insert into '%s' values('%s');", tab_name, my_info->uid);
    ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg);
    if (ret != SQLITE_OK) {
        syslog(LOG_ERR, "error: %s\n", errmsg);
        return -1;
    }

    // 关闭数据�?
    sqlite3_close(ppdb);

    // 当双方添加好友后，需要在各自的数据库中，创建一个名为_uid的表
    // 在my数据库中创建_brouid�?
    // 1. 确定数据库名�?
    sqlite3 *ppDb;
    char sql_name[60] = {0};
    strcpy(sql_name, my_info->uid);
    strcat(sql_name, ".db");
    // 2. 打开my数据�?
    sqlite3_open(sql_name, &ppDb);
    // 3. 确定表名
    bzero(tab_name, sizeof(tab_name));
    strcpy(tab_name, "_");
    strcat(tab_name, bro_info.uid);
    // 4. 创建_brouid�?
    sprintf(sql, "create table if not exists '%s'(status int, message char[110]);", tab_name);
    ret = sqlite3_exec(ppDb, sql, NULL, NULL, &errmsg);
    if (ret != SQLITE_OK) {
        syslog(LOG_ERR, "error: %s\n", errmsg);
        // 关闭日志
        closelog();
        // 关闭数据�?
        sqlite3_close(ppDb);
        return -1;
    }
    sqlite3_close(ppDb);
    // 在brouid数据库中创建_myuid�?
    // 1. 确定数据库名�?
    bzero(sql_name, sizeof(sql_name));
    strcpy(sql_name, bro_info.uid);
    strcat(sql_name, ".db");
    // 2. 打开my数据�?
    sqlite3_open(sql_name, &ppDb);
    // 3. 确定表名
    bzero(tab_name, sizeof(tab_name));
    strcpy(tab_name, "_");
    strcat(tab_name, my_info->uid);
    // 4. 创建_myuid�?
    sprintf(sql, "create table if not exists '%s'(status int, message char[110]);", tab_name);
    ret = sqlite3_exec(ppDb, sql, NULL, NULL, &errmsg);
    if (ret != SQLITE_OK) {
        syslog(LOG_ERR, "error: %s\n", errmsg);
        // 关闭日志
        closelog();
        // 关闭数据�?
        sqlite3_close(ppDb);
        return -1;
    }

    // 关闭日志
    closelog();
    // 关闭数据�?
    sqlite3_close(ppDb);
    return 0;
}

int del_bro(void *info)
{
    struct user *my_info = (struct user *)info;
    // 打开日志
    openlog("ikun", LOG_PID, LOG_DAEMON);

    // 打开数据�?
    sqlite3 *ppdb;
    char *errmsg;
    sqlite3_open("uid.db", &ppdb); // 打开数据�?

    // 接收好友的uid
    struct user bro_info;
    info_recv(my_info->fd, &bro_info);

  /*
  //根据自己的fd, 找到uid，再确认自己�?<用户好友�?>
  //1.根据fd，确定自己的uid
      struct user my_info = {0};  //声明信息结构�?
      char sql[200];           //sql操作
      bzero(sql,sizeof(sql));
      sprintf(sql, "select * from sign_in where user_fd=='%d';", my_info->fd);

      int ret = sqlite3_exec(ppdb, sql, my_uid, &my_info,
  &errmsg);//查询自己的uid if(ret != SQLITE_OK){ syslog(LOG_ERR, "error: %s\n",
  errmsg);
      //关闭日志
      closelog();
      //关闭数据�?
      sqlite3_close(ppdb);
      return -1;
  }//my_info.uid中保存了自己的uid
  */

    // 2. 用户根据uid确定自己的好友表表名
    char tab_name[60] = "_";        // 表名以_开�?
    strcat(tab_name, my_info->uid); // tab_name是用户好友表的表�?

    // 3. 判断好友uid是否存在于好友表�?
    char sql[200];
    bzero(sql, sizeof(sql));
    sprintf(sql, "select * from '%s';", tab_name); // 查询自己的好友表中是否存在待添加用户uid
    int ret = sqlite3_exec(ppdb, sql, compare_uid, &bro_info, &errmsg);
    if (ret != SQLITE_OK) { // 若回调函数中途退出，则说明好友uid存在于好友表�?
        // 4. 删除用户好友表中的好友uid
        bzero(sql, sizeof(sql));
        sprintf(sql, "delete from '%s' where user_uid == '%s';", tab_name, bro_info.uid);
        ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK) {
            syslog(LOG_ERR, "error: %s\n", errmsg);
            // 关闭日志
            closelog();
            // 关闭数据�?
            sqlite3_close(ppdb);
            return -1;
        }
        // 5. 删除好友<用户好友�?>中自己的uid
        // 根据好友uid确定好友的《用户好友表》表�?
        char tab_name[60] = "_";        // 表名以_开�?
        strcat(tab_name, bro_info.uid); // tab_name是用户好友表的表�?

        // 删除用户好友表中的好友uid
        bzero(sql, sizeof(sql));
        sprintf(sql, "delete from '%s' where user_uid == '%s';", tab_name, my_info->uid);
        ret = sqlite3_exec(ppdb, sql, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK) {
            syslog(LOG_ERR, "error: %s\n", errmsg);
            // 关闭日志
            closelog();
            // 关闭数据�?
            sqlite3_close(ppdb);
            return -1;
        }
        // 返回删除成功信息
        sig_send(my_info->fd, "del ok");
    } else { // 待删除好友不在用户好友表中，返回删除失败信号
        sig_send(my_info->fd, "del error"); // 给用户发送添加失败信�?---该用户不存在�?
        // 关闭日志
        closelog();
        // 关闭数据�?
        sqlite3_close(ppdb);
        return -1;
    }
    // 关闭日志
    closelog();
    // 关闭数据�?
    sqlite3_close(ppdb);

    return 0; // 删除成功返回0
}
